package com.hl.payServer.security;


import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;

/**
 * MD5withRSA 平安银行使用签名
 * @author Administrator
 *
 */
public class MD5withRSA {


	
	public static void main(String[] args) {
		//私钥加密
		KeyStore keyStore = MD5withRSA.init("D:/merchant.jks", "changeit");//初骀化  
		String info = "需要加密的字符串";
		String m = MD5withRSA.signDataRSA("mykey","changeit",info,keyStore);//加密
		boolean isVer = MD5withRSA.verifyDataRSA("mykey", m, info, keyStore);
		System.out.println(m);
		System.out.println(isVer);
	}
	
	/**
	 * 初始化keyStore
	 * @param keyFilePath
	 * @param keyStore_password
	 */
	public static KeyStore init(String keyFilePath, String keyStore_password) {
		InputStream inputStream = null;
		try {
			inputStream = new FileInputStream(keyFilePath);
		} catch (FileNotFoundException e) {
			System.err.println("Error in MerSignVerify CA File Not Found");
			e.printStackTrace();
		}
		char[] pass = keyStore_password == null ? null : keyStore_password
				.toCharArray();
		KeyStore keyStore = null;
		try {
			keyStore = KeyStore.getInstance("JKS");
			keyStore.load(inputStream, pass);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return keyStore;
	}
	
	
	
//	public static String merchantSignData_ABA(String alias, String password,String data) {
////		KeyStoreUtil_ABA ks = null;
////		try {
////			ks = new KeyStoreUtil_ABA(keyStore);
////		} catch (Exception e) {
////			return null;
////		}
////		return ks.signDataRSA(alias, password, data);
//		return signDataRSA(alias, password, data);
//	}
	
	
//	public void KeyStoreUtil_ABA(KeyStore keyStore) throws KeyStoreException {
//		this.keyStore = keyStore;
//		Enumeration enu = keyStore.aliases();
//
//		while (enu.hasMoreElements()) {
//			String alias = (String) enu.nextElement();
//
//			if (keyStore.isCertificateEntry(alias)) {
//				CertificateInfo ci = new CertificateInfo();
//				ci.setAlias(alias);
//				ci.setCertificate(keyStore.getCertificate(alias));
//				ci.setCertificateChain(keyStore.getCertificateChain(alias));
//				ci.setCreationDate(keyStore.getCreationDate(alias));
//				this.certificateEntry.put(alias, ci);
//			}
//
//			if (keyStore.isKeyEntry(alias)) {
//				KeyInfo ki = new KeyInfo();
//				ki.setAlias(alias);
//				ki.setCreationDate(keyStore.getCreationDate(alias));
//				this.keyEntry.put(alias, ki);
//			}
//		}
//	}
	/**
	 * 根据别名和密码取公钥验签
	 * @param alias
	 * @param signData
	 * @param orgData
	 * @param keyStore
	 * @return
	 */
	public static boolean verifyDataRSA(String alias, String signData, String orgData, KeyStore keyStore) {
		try {
			if ((alias == null) || (signData == null) || (orgData == null)) {
				System.err.println("Error:in KeyStoreUtil.verifyDataRSA() . alias or signData or orgData is null");
				return false;
			}

			System.err.println(signData);
			System.err.println(orgData);

			PublicKey publicKey = keyStore.getCertificate(alias).getPublicKey();

			return verifyData(publicKey, signData, orgData, "MD5withRSA");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}
	
	/**
	 * 验签
	 * @param publicKey
	 * @param signData
	 * @param orgData
	 * @param alg
	 * @return
	 */
	private static boolean verifyData(PublicKey publicKey, String signData, String orgData, String alg) {
		try {
			if ((publicKey == null) || (signData == null) || (orgData == null)
					|| (alg == null)) {
				System.err
						.println("Error:in KeyStoreUtil.verifyData() . publicKey or signData or orgData or alg is null");
				return false;
			}

			Signature dsa = Signature.getInstance(alg);

			dsa.initVerify(publicKey);

			dsa.update(orgData.getBytes("GBK"));

			byte[] sig = hexToByte(signData);
			return dsa.verify(sig);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}
	
	/**
	 * 根据别名和密码取私钥进行签名
	 * @param alias
	 * @param password
	 * @param data
	 * @return
	 */
	public static String signDataRSA(String alias, String password, String data, KeyStore keyStore) {
		if ((alias == null) || (password == null) || (data == null)) {
			return null;
		}

		PrivateKey privateKey = getPrivateKey(alias, password, keyStore);

		if (privateKey == null) {
			System.err.println("The alias or password is wrong");
			return null;
		}

		System.err.println("Private Key:" + privateKey.getClass().getName());

		if (!(privateKey instanceof RSAPrivateKey)) {
			System.err.println("The key is not RSAPrivateKey");
			System.err.println("The class should Run under ABA");
			return null;
		}

		return signData(privateKey, data, "MD5withRSA");
	}
	
	/**
	 * 签名
	 * @param privateKey
	 * @param data
	 * @param alg
	 * @return
	 */
	private static String signData(PrivateKey privateKey, String data, String alg) {
		try {
			Signature dsa = Signature.getInstance(alg);

			dsa.initSign(privateKey);

			dsa.update(data.getBytes("GBK"));

			byte[] sig = dsa.sign();

			return byteToHex(sig);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 取得私钥
	 * @param alias
	 * @param password
	 * @return
	 */
	private static PrivateKey getPrivateKey(String alias, String password, KeyStore keyStore) {
		if ((alias == null) || (password == null)) {
			return null;
		}
		try {
			return (PrivateKey) keyStore.getKey(alias,
					password.toCharArray());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public static String byteToHex(byte[] inbuf) {
		StringBuffer strBuf = new StringBuffer();

		for (int i = 0; i < inbuf.length; i++) {
			String byteStr = Integer.toHexString(inbuf[i] & 0xFF);
			if (byteStr.length() != 2) {
				strBuf.append('0').append(byteStr);
			} else {
				strBuf.append(byteStr);
			}
		}
		return new String(strBuf);
	}
	
	public static byte[] hexToByte(String inbuf) {
		int len = inbuf.length() / 2;
		byte[] outbuf = new byte[len];

		for (int i = 0; i < len; i++) {
			String tmpbuf = inbuf.substring(i * 2, i * 2 + 2);
			outbuf[i] = ((byte) Integer.parseInt(tmpbuf, 16));
		}

		return outbuf;
	}
}